import hashlib
import os
import re
import zipfile
import argparse

"""
检查lib或者Spring boot jar中重复的包，避免版本冲突
"""
jar_path = [
    '/xxx/lib',
    '/xxx/xx.jar',
]


def file_hash(file_path):
    with open(file_path, 'rb') as f:
        return hashlib.md5(f.read()).hexdigest()


def parse_jar_name_and_version(_jar_path):
    """
    解析 JAR 包的名称和版本号。
    """
    try:
        version = None
        filename = os.path.basename(_jar_path)
        version_match = re.search(r"^(.*)-(\d+(?:\.(\w|-)+)*)\.jar$", filename)
        version = version_match.group(2).strip() if version_match else None
        # 从文件名中提取 JAR 包名称 (移除 .jar 扩展名)
        name = version_match.group(1).strip() if version_match else None
        if not name:
            print(f'{filename} name is not found!')
            name = filename.replace('.jar', '')
        if not version:
            print(f'{filename} version is not found!')
        if os.path.isfile(_jar_path):
            with zipfile.ZipFile(_jar_path, 'r') as jar_file:
                # 尝试从 MANIFEST.MF 文件中读取版本信息
                if not version:
                    try:
                        manifest_data = jar_file.read('META-INF/MANIFEST.MF').decode('utf-8')
                        version_match = re.search(r"Implementation-Version: (.*)", manifest_data)
                        version = version_match.group(1).strip() if version_match else None
                    except Exception:
                        pass
                if not version:
                    try:
                        # 如果pom.xml中没有找到，尝试从pom.properties中提取信息
                        properties_files = [name for name in jar_file.namelist() if name.endswith('/pom.properties')]
                        if properties_files:
                            properties_file_path = properties_files[0]
                            with jar_file.open(properties_file_path) as properties:
                                properties_content = properties.read().decode('utf-8')

                                group_id_match = re.search(r'groupId=(.+)', properties_content)
                                artifact_id_match = re.search(r'artifactId=(.+)', properties_content)
                                version_match = re.search(r'version=(.+)', properties_content)

                                if group_id_match and artifact_id_match and version_match:
                                    group_id = group_id_match.group(1).strip()
                                    artifact_id = artifact_id_match.group(1).strip()
                                    version = version_match.group(1).strip()
                    except Exception:
                        pass
        return {'name': name, 'version': version}

    except (zipfile.BadZipFile, FileNotFoundError) as e:
        print(f"Error processing JAR file: {e}")
        return None, None


def list_files_in_jar(_jar_path, target_dir):
    """
    列出JAR包中指定目录下的文件列表。

    :param _jar_path: JAR文件的路径
    :param target_dir: 目标目录（例如 'com/example/'）
    :return: 文件列表
    """
    file_list = []
    with zipfile.ZipFile(_jar_path, 'r') as jar:
        # 遍历JAR包中的所有文件
        for file_info in jar.infolist():
            # 检查文件是否在目标目录下
            if file_info.filename.startswith(target_dir):
                if not file_info.is_dir():
                    file_list.append(file_info.filename)
    return file_list


def check_duplicat(path):
    hash_map = {}
    if path.endswith('.jar'):
        namelist = list_files_in_jar(path, 'BOOT-INF/lib')
        for file in namelist:
            if file.endswith('.jar'):
                version_info = parse_jar_name_and_version(f'{file}')
                if version_info.get('name') in hash_map:
                    duplicate_versions = []
                    duplicate_versions.append(version_info.get("version"))
                    duplicate_versions.append(hash_map.get(version_info.get("name")))
                    print(f'duplicate jar: {version_info.get("name")}, versions: {duplicate_versions}')
                else:
                    hash_map.update({version_info.get('name'): version_info.get('version')})
    else:
        for file in os.listdir(path):
            version_info = parse_jar_name_and_version(f'{path}/{file}')
            if version_info.get('name') in hash_map:
                duplicate_versions = []
                duplicate_versions.append(version_info.get("version"))
                duplicate_versions.append(hash_map.get(version_info.get("name")))
                print(f'duplicate jar: {version_info.get("name")}, versions: {duplicate_versions}')
            else:
                hash_map.update({version_info.get('name'): version_info.get('version')})


def check_exists(path, name):
    names = []
    if path.endswith('.jar'):
        namelist = list_files_in_jar(path, 'BOOT-INF/lib')
        for file in namelist:
            if file.endswith('.jar'):
                if re.search(name, file):
                    names.append(file)
    else:
        for file in os.listdir(path):
            if file.endswith('.jar'):
                if re.search(name, file):
                    names.append(file)
    return names


def check_exists_all(name):
    for path in jar_path:
        if not os.path.exists(path):
            print(f'path {path} is not exists')
            continue
        names = check_exists(path, name)
        if len(names) > 0:
            print(f'jar {name} exists in {path}, names: {names}')
    print(f'all done.')


def check_duplicat_all():
    for path in jar_path:
        print(f'checking path {path}...')
        if not os.path.exists(path):
            print(f'path {path} is not exists')
            continue
        check_duplicat(path)
    print(f'all done.')


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='扫描重复的jar包或者查找jar包是否存在')
    parser.add_argument('-n', '--name', help='扫描jar存在哪些目录中')
    args = parser.parse_args()
    name = args.name
    if name:
        check_exists_all(name)
    else:
        check_duplicat_all()
